﻿// ===============================================================================
// DotNet.Platform 开发框架 2016 版权所有
// ===============================================================================

using System;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using System.Reflection;

namespace DotNet.DataAnnotationsExtensions
{
    public class CompareDateAttribute : ValidationAttribute
    {
        public CompareDateAttribute(string otherProperty,
            DateCompareType dateCompareType)
        {
            if (otherProperty == null)
            {
                throw new ArgumentNullException(nameof(otherProperty));
            }
            OtherProperty = otherProperty;
            CompareType = dateCompareType;
        }

        public string OtherProperty { get; private set; }

        public DateCompareType CompareType { get; private set; }
        
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            var memberNames = new[] { validationContext.MemberName };

            PropertyInfo otherPropertyInfo = validationContext.ObjectType.GetProperty(OtherProperty);
            if (otherPropertyInfo == null)
            {
                return new ValidationResult(String.Format(CultureInfo.CurrentCulture,
                    "找不到指定的属性名称 {0}.", OtherProperty), memberNames);
            }

            #region if (ErrorMessage == null)

            if (ErrorMessage == null)
            { 
                var otherDisplayAttribute =
                otherPropertyInfo.GetCustomAttributes(typeof(DisplayAttribute), false).FirstOrDefault() as DisplayAttribute;

                var otherPropertyDisplayName = OtherProperty;
                var displayName = validationContext.DisplayName;
                if (otherDisplayAttribute != null && !string.IsNullOrWhiteSpace(otherDisplayAttribute.Name))
                {
                    otherPropertyDisplayName = otherDisplayAttribute.Name;
                }

                #region ErrorMessage

                switch (CompareType)
                {
                    case DateCompareType.GreatThan:
                        ErrorMessage = $"{displayName}必须大于{otherPropertyDisplayName}.";
                        break;
                    case DateCompareType.GreatThanEquals:
                        ErrorMessage = $"{displayName}必须大于等于{otherPropertyDisplayName}.";
                        break;
                    case DateCompareType.LessThan:
                        ErrorMessage = $"{displayName}必须小于{otherPropertyDisplayName}.";
                        break;
                    case DateCompareType.LessThanEquals:
                        ErrorMessage = $"{displayName}必须小于等于{otherPropertyDisplayName}.";
                        break;
                    default:
                        ErrorMessage = $"{displayName}必须等于{otherPropertyDisplayName}.";
                        break;
                }

                #endregion
            }

            #endregion

            object otherPropertyValue = otherPropertyInfo.GetValue(validationContext.ObjectInstance, null);
            if (value == null || otherPropertyValue == null) return null;
            DateTime d1;
            DateTime d2;
            DateTime.TryParse(Convert.ToString(otherPropertyValue), out d1);
            DateTime.TryParse(Convert.ToString(value), out d2);
            
            #region CompareType

            switch (CompareType)
            {
                case DateCompareType.GreatThan:
                    if (!(d2 > d1))
                    {
                        return new ValidationResult(ErrorMessage);
                    }
                    break;
                case DateCompareType.GreatThanEquals:
                    if (!(d2 >= d1))
                    {
                        return new ValidationResult(ErrorMessage);
                    }
                    break;
                case DateCompareType.LessThan:
                    if (!(d2 < d1))
                    {
                        return new ValidationResult(ErrorMessage);
                    }
                    break;
                case DateCompareType.LessThanEquals:
                    if (!(d2 <= d1))
                    {
                        return new ValidationResult(ErrorMessage);
                    }
                    break;
                case DateCompareType.Equals:
                    if (!(d2 == d1))
                    {
                        return new ValidationResult(ErrorMessage);
                    }
                    break;
                default:
                    return null;
            }

            #endregion

            return null;
        }
    }

    /// <summary>
    /// 日期比较类型
    /// </summary>
    public enum DateCompareType
    {
        /// <summary>
        /// 大于
        /// </summary>
        GreatThan,

        /// <summary>
        /// 大于等于
        /// </summary>
        GreatThanEquals,

        /// <summary>
        /// 小于
        /// </summary>
        LessThan,

        /// <summary>
        /// 小于等于
        /// </summary>
        LessThanEquals,

        /// <summary>
        /// 等于
        /// </summary>
        Equals
    }
}